package com.aop.aop;


import com.aop.utils.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
 * @Description:
 * @author: zxl
 * @Data:2021/3/23
 */

/**
 * 记录一次请求中,流经的所有方法的调用耗时及次数
 */
//@Component
//@Aspect
@Slf4j
public class ControllerInterceptor3 {
    private Map<String, Integer> methodCount = new ConcurrentHashMap();

    private Map<String, List<Integer>> methodCost = new ConcurrentHashMap();

    @SuppressWarnings(value = "unchecked")

    @Around("@annotation(com.aop.annotation.MethodMeasureAnnotation)")
    public Object process(ProceedingJoinPoint joinPoint) {

        Object obj = null;

        String className = joinPoint.getTarget().getClass().getSimpleName();

        String methodName = className + "_" + getMethodName(joinPoint);

        long startTime = System.currentTimeMillis();

        try {

            obj = joinPoint.proceed();

        } catch (Throwable t) {
            log.error(t.getMessage(), t);
        } finally {
            long costTime = System.currentTimeMillis() - startTime;
            log.info("method={}, cost_time={}", methodName, costTime);
            methodCount.put(methodName, methodCount.getOrDefault(methodName, 0) + 1);
            List<Integer> costList = methodCost.getOrDefault(methodName, new ArrayList<>());
            costList.forEach(item -> {
                System.out.println("count: " + item);
            });
            costList.add((int) costTime);
            methodCost.put(methodName, costList);
            methodCost.forEach((key, value) -> {
                System.out.println(key + ":" + value);
            });
        }
        return obj;
    }

    public String getMethodName(ProceedingJoinPoint joinPoint) {

        Signature signature = joinPoint.getSignature();

        MethodSignature methodSignature = (MethodSignature) signature;

        Method method = methodSignature.getMethod();

        return method.getName();

    }

    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder("MethodCount:\n");

        Map<String, Integer> sorted = MapUtil.sortByValue(methodCount);

        sorted.forEach(

                (method, count) -> {

                    sb.append("method=" + method + ", " + "count=" + count + '\n');

                }

        );

        sb.append('\n');

        sb.append("MethodCosts:\n");

        methodCost.forEach(

                (method, costList) -> {

                    IntSummaryStatistics stat = costList.stream().collect(Collectors.summarizingInt(x -> x));

                    String info = String.format("method=%s, sum=%d, avg=%d, max=%d, min=%d, count=%d", method,

                            (int) stat.getSum(), (int) stat.getAverage(), stat.getMax(), stat.getMin(), (int) stat.getCount());

                    sb.append(info + '\n');

                }

        );

        sb.append('\n');

        sb.append("DetailOfMethodCosts:\n");

        methodCost.forEach(

                (method, costList) -> {

                    String info = String.format("method=%s, cost=%s", method, costList);

                    sb.append(info + '\n');

                }

        );

        return sb.toString();

    }

}



